home *** CD-ROM | disk | FTP | other *** search
- From: "Art Eschenlauer" <eschen@molbio.cbs.umn.edu>
- Subject: Routines that open blocks as filestreams in ThC 5
- Date: Sat, 24 Sep 1994 12:31:39 -0500 (CDT)
-
- Here's a file to put into /mac/development/sources/snippets on
- mac.archive.umich.edu. Compress it as you please.
-
-
- /*
- blockio.c and blockio.h by Art Eschenlauer
-
- Routines to open blocks of memory as simple filestreams under ThinkC 5.0.4
-
- Here are some routines to open a block of memory (Ptr or Handle) as a simple
- filestream (they do not support disk oriented commands like rewind and seek).
- I wrote these for porting unix software to ThinkC 5.0.4 using the standard
- libraries. I don't know if they would work on later versions of ThinkC std
- libraries. Bugs, comments, flames, etc. to eschen@molbio.cbs.umn.edu.
-
- Disclaimer:
-
- ++++++++++ NOTICE - GRATIS EXPERIMENTAL SOFTWARE ++++++++++
-
- THIS IS EXPERIMENTAL SOFTWARE THAT IS PROVIDED "AS IS" FOR YOUR USE, GRATIS. NO
- WARRANTY OR REPRESENTATION WHATSOEVER, EITHER EXPRESS OR IMPLIED, IS GIVEN WITH
- RESPECT TO THIS SOFTWARE, ITS QUALITY, PERFORMANCE, MERCHANTABILITY, OR FITNESS
- FOR A PARTICULAR PURPOSE. IF YOU CHOOSE TO USE IT, YOU ASSUME ALL RISKS AS TO
- ITS QUALITY AND PERFORMANCE, INCLUDING (BUT NOT LIMITED TO) LOST TIME, DATA,
- MONEY, AND USE OF, OR DAMAGE TO, YOUR COMPUTER, YOUR BRAIN, ETC.. NO ONE SHALL
- IN ANY EVENT BE HELD LIABLE FOR ANY DAMAGE OR LOSS THAT MAY BE CAUSED BY, OR
- MAY BE ASSOCIATED WITH, THIS SOFTWARE.
-
- Translation: you didn't pay (or shouldn't have paid) for this EXPERIMENTAL
- software, so it's up to you to cover any damages. While I have tested this
- software (somewhat) and have no malicious intent in providing this software,
- excrement transpires, and it's up to you to wipe it up. YOU MAY NOT USE THIS
- SOFTWARE IF YOU DO NOT AGREE WITH THE ABOVE.
- */
- /*-snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip-*/
- /*
- * blockio.h - filestream i/o for pointers to memory blocks
- * Interface to public routines defined in blockio.c
- *
- * ThinkC 5.0.4, 7 June 1994
- * notcopyright (!)) 1994 Art Eschenlauer - PUBLIC DOMAIN!!!!
- *
- * These routines are to support filestream i/o operations
- * to pointers, in the same manner that
- * <console.c> supports filestream io to the console interface and
- * <fopen.c> supports filestream io to macintosh files and
- * <stdio.c> supports filestream io to c-strings
- *
- * These routines require that blocks be allocated as Ptr's or Handle's
- * (excepting for freopenblock).
- *
- * I suggest that you may want to close output streams like so
- * fputc(0,theBlockStream); fclose(theBlockStream);.
- * Caveat emptor!!
- */
- #ifndef __BLOCKSTREAM__
- #define __BLOCKSTREAM__ 1
-
- #include <stdio.h>
-
- //// Routines for dealing with Ptr's ////
- // (For Handle's, see below)
-
- // fopenPtr - open a (nonrelocatable) block of memory as a filestream
- // theBlockPtr is a Ptr to the block of memory
- // mode is "r", "w", "rb", or "wb"
- // (Nonrelocatable blocks cannot be opened in append mode.)
-
- FILE *
- fopenPtr( const Ptr theBlockPtr, const char *mode );
-
- // freopenPtr - open a (nonrelocatable) block of memory as a filestream
- // using the file table pointed by fp.
- // theBlockPtr is a Ptr to the block of memory
- // mode is "r", "w", "rb", or "wb"
- // (Don't reopen stdin as "w" or "a" or reopen stdout or stderr as "r"!)
-
- FILE *
- freopenPtr( const Ptr theBlock, const char *mode, FILE *fp );
-
-
- //// Routine for dealing with block of memory not allocated as Ptr ////
-
- // freopenblock - open a (nonrelocatable) block of memory as a filestream
- // using the file table pointed by fp.
- // theBlock is a Ptr to the block of memory
- // mode is "r", "w", "rb", or "wb"
- // NEVER use theBlockSize < 0 or theBlockSizeIncrement != 0, and be sure
- // that fp, theBlock, and mode are valid
- FILE *
- freopenblock( const char *theBlock, const char *mode, Size theBlockSize,
- Size theBlockSizeIncrement, FILE *fp );
-
-
- //// Routines for dealing with Handle's ////
-
- /*
- * Note Well:
- *
- * Do not unlock relocatable blocks till after the filestream is closed!!
- * Do NOT assume that they do not relocate while the filestream is open!!
- * Only relocatable blocks (Handles) can be expanded as need be.
- * theBlockSizeIncrement (which specifies how much to grow the block
- * each time) must be nonzero for expansion of relocatable blocks;
- * use zero for theBlockSizeIncrement if using modes "r" or "w".
- */
-
- // fopenHandle - open a relocatable block of memory as a filestream
- // theBlockHandle is a Handle to the block of memory
- // mode is "r", "w", or "a"
- // (Only relocatable blocks can be opened in append mode.)
-
- FILE *
- fopenHandle( const Handle theHandle, const char *mode,
- Size theBlockSizeIncrement );
-
- // freopenHandle - open a block of memory as a filestream
- // using the file table pointed by fp.
- // theBlockPtr is a pointer to the block of memory
- // mode is "r", "w", "a", "rb", "wb", "ab"
- // (Don't reopen stdin as "w" or "a" or reopen stdout or stderr as "r"!)
-
- FILE *
- freopenHandle( const Handle theHandle, const char *mode,
- Size theBlockSizeIncrement, FILE *fp );
-
- #endif __BLOCKSTREAM__
- /*-snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip-*/
-
-
- /*
- * blockio.c - filestream i/o for pointers to memory blocks
- * notcopyright (!)) 1994 Art Eschenlauer - PUBLIC DOMAIN!!!!
- * see "blockio.h" for usage info
- * ThinkC 5.0.4, 6 June 1994
- *
- * To link successfully, projects using blockio.c must include the oops library.
- */
-
- // stdio.h defines BUFSIZE and _IOFBF
- #include <stdio.h>
- #include <ansi_private.h>
- #include <errno.h>
- #include <string.h>
-
- // convenience includes
- //#include <Memory.h>
- // typedef long Size (see Memory.h)
- // typedef unsigned long size_t (see size_t.h)
-
-
- /// PRIVATE ROUTINE PROTOTYPES AND CLASS DECLARATION ///
-
- // i/o routine that is assigned to fp->proc
- static int
- blockio( FILE *fp, int i );
-
- // setupblockfp actually does the work of setting up the file
- // table entry so that an entry can use a block of
- // memory, pointed by theBlockPtr and of size theBlockSize,
- // as the input filestream or output filestream:
-
- static FILE *
- setupblockfp( FILE *fp, const char *s, Size theBlockSize,
- Size theBlockSizeIncrement, Boolean _APPENDMODE );
-
- // Cblock class - I do not intend other functions to use the Cblock class
- // I really only used it to dynamically allocate a structure that can be
- // referenced using fp->long in the file table. If you want to use it in other
- // functions, remove it from blockio.c and put it in blockio.h
-
- class Cblock : direct {
- public:
-
- /// Instance variables ///
-
- char *start; // first byte in block
- char *pos; // current position to read/write in block of memory
- char *end; // last byte in block
- Size increment; // size by which block is to expand if space runs out
- // (nonzero only if block is Handle opened for append)
- Handle hblock; // handle to block if block is relocatable
- char hstate; // state of handle (locked etc.) before opening block stream
-
- /// Methods ///
-
- // initialize Cblock object, true if succeeds
- Boolean Iblock( const char *s, Size theBlockSize,
- Size theBlockSizeIncrement, Boolean _APPENDMODE );
-
- // destruct Cblock object
- void Dblock(void);
-
- };
-
-
- /// PUBLIC ROUTINE PROTOTYPES ///
- #ifndef __BLOCKSTREAM__
- #include "blockio.h"
- #endif __BLOCKSTREAM__
-
-
- /// PRIVATE ROUTINE DEFINITIONS ///
-
- /* blockio - I/O proc installed into FILE structure, so that __read,
- * __write, and __close will all work with the block of memory
- * (see bufio.c).
- *
- * this is set up to point to the block associated with the fp
- */
- static int
- blockio(FILE *fp, int i)
- {
- int result;
- register Cblock *this;
- register int counter;
-
- // recover reference to the object associated with the filepointer
- this = (Cblock *) fp->window;
-
- result = 0;
- switch(i)
- {
- case 0: //read
-
- //handle EOF case
- if (this->pos >= this->end)
- { fp->cnt = 0; fp->eof = 1; return EOF; }
- //determine # bytes to read
- counter = fp->cnt = (fp->size > (this->end - this->pos)) ?
- this->end - this->pos : fp->size;
- //transfer bytes to buffer
- while (counter--)
- *(fp->ptr++) = *(this->pos++);
- //reset fp->ptr
- fp->ptr = (unsigned char *) fp->buf;
- fp->eof = 0;
-
- if (!fp->binary)
- {
- #pragma options(honor_register)
- register unsigned char *s;
- register size_t n;
- register unsigned char *t;
- n = fp->cnt;
- s = (unsigned char *) fp->buf;
- for (; n && (t = memchr(s, '\r', n)); s = t)
- {
- *t++ = '\n';
- n -= t - s;
- }
- }
-
- break; //(switch)
-
- case 1: //write
-
- // tryagain loop begins here
- tryagain:
- if ((counter = fp->cnt) > (this->end - this->pos))
- {
- if( this->increment )
- { // attempt to expand Handle size
- // and, if successful, try output again
-
- Size oldHandleSize;
-
- HUnlock( this->hblock );
- SetHandleSize( this->hblock, this->increment
- + ( oldHandleSize = GetHandleSize( this->hblock ) ) );
- HLock( this->hblock );
-
- if (oldHandleSize == GetHandleSize( this->hblock ))
-
- goto bail; // break from tryagain loop
-
- // (else)
- this->end += ( *this->hblock - this->start );
- this->pos += ( *this->hblock - this->start );
- this->start = *this->hblock;
- fp->len += this->increment;
- this->end += this->increment;
-
- goto tryagain; // loop back to tryagain
-
- // tryagain loop ends here
- }
-
- bail:
- // write all you can, and
- // update result, counter, fp->cnt, fp->eof, and fp->pos
- // to reflect end of file condition
-
- result = EOF;
- fp->pos -= fp->cnt -= (counter = this->end - this->pos);
- fp->eof = 1;
- }
- else
- // fp->cnt <= (this->end - this->pos)
- fp->cnt = 0;
-
-
- // counter (set at tryagain) holds number of bytes to transfer
- // from buffer to block
-
- if (!fp->binary)
- {
- #pragma options(honor_register)
- register unsigned char *s;
- register size_t n;
- register unsigned char *t;
- n = counter;
- s = (unsigned char *) fp->buf;
- for (; n && (t = memchr(s, '\n', n)); s = t)
- {
- *t++ = '\r';
- n -= t - s;
- }
- }
-
- while (counter--)
- *(this->pos++) = *(fp->ptr++);
- break; // (switch)
-
- case 2: //close
-
- //close filestream and delete object
- memset(fp,0,sizeof(FILE));
- __checkfile(fp);
- this->Dblock();
- }
- bye:
- return result;
- }
-
- static FILE *
- setupblockfp( FILE *fp, const char *s, Size theBlockSize,
- Size theBlockSizeIncrement, Boolean _APPENDMODE )
- { /*
- setupblockfp creates and initializes the block data structure and the
- corresponding file structure. Actually, initialization of the block
- datastructure is delegated to the Iblock method, and setting up of the
- fp itself is handled by setupblockfp itself.
- */
- Cblock *Oblock;
-
- //create and initialize Oblock object
- // that will implement io for block
- Oblock = new Cblock;
- if ( Oblock != NULL )
- {
- if ( Oblock->Iblock( s, theBlockSize, theBlockSizeIncrement, _APPENDMODE ) )
- {
- /// set up fp ///
- // set every fp->thing to zero
- memset(fp, 0, sizeof(FILE));
-
- fp->len = ( theBlockSize > 0 ) ? theBlockSize : - theBlockSize ;
-
- /* __checkfile sets
- fp->ptr = fp->buf = &fp->one, fp->size = 1, fp->proc = nullio
- */
- __checkfile(fp);
-
- //fp->refnum for a disk file >0, for an open stream !=0
- fp->refnum = -1;
-
- //vectored routine (io proc) for block i/o
- fp->proc = blockio;
-
- // store object reference in fp->window
- // so that the blockio proc can recover it
- fp->window = (void *) Oblock;
-
- return fp;
-
- }
- Oblock->Dblock();
- }
- return NULL;
- }
-
- /*
- Cblock::Iblock - set up instance variables for block i/o:
- Meanings of arguments:
- blocksize < 1: handle size-expansion is possible
- theBlockSizeIncrement > 0: handle size-expansion is requested
- _APPENDMODE == 1: start writing at the end of block instead of beginning
- */
- Boolean
- Cblock::Iblock(const char *s, Size theBlockSize,
- Size theBlockSizeIncrement, Boolean _APPENDMODE )
- {
-
- if (theBlockSize > 0)
- {
- this->hblock = NULL;
- this->start = (char *) s;
- }
- else
- {
- this->hblock = (Handle) s;
- this->hstate = HGetState( this->hblock );
- HLock( this->hblock );
- this->start = (char *) *( this->hblock );
- }
-
- this->end =
- (
- this->start +
- ( ( this->hblock ) ? - theBlockSize : theBlockSize )
- );
-
- this->pos = _APPENDMODE ? this->end : this->start ;
-
- // only handles can be resized because only handles can be relocated
- this->increment = theBlockSizeIncrement;
-
- return true;
- }
-
- /* Cblock::Dblock - destruct Cblock object */
- void
- Cblock::Dblock()
- {
- // restore state to what it was before the Cblock->Iblock call
- if( this->hblock )
- HSetState( this->hblock, this->hstate );
-
- delete this; // self destruct
- }
-
-
- /// PUBLIC ROUTINE DEFINITIONS ///
-
- FILE *
- freopenblock( const char *theBlock, const char *mode, Size theBlockSize,
- Size theBlockSizeIncrement, FILE *fp ) {
-
- // if freopenblock fails, *fp is closed nevertheless...
-
- //be sure it is clear what to work with
- if (fp==NULL) goto fail2;
-
- //do not open console if you do not have to
- fp->std = 0;
- fclose(__checkfile(fp));
-
- /* interpret "rwa" */
- // not yet set up for update editing...
-
- switch ( mode[0] )
- {
- case 'r':
- case 'R':
- case 'w':
- case 'W':
-
- // r & w require nonzero length blocks and zero expansion increment,
- // respectively
- if ( (0 == theBlockSize) || (0 != theBlockSizeIncrement) ) goto fail;
-
- setupblockfp( fp, theBlock, theBlockSize, 0, false );
- break; // switch
-
- case 'a':
- case 'A':
-
- // append requires handles and nonzero expansion increment, respectively
- if ( (theBlockSize > 0) || (0 == theBlockSizeIncrement) ) goto fail;
-
- if ( setupblockfp( fp, ( char *) theBlock, theBlockSize,
- theBlockSizeIncrement, true ) )
- {
- // the only good way out of here
- fp->append = 1;
- fp->pos = fp->len;
- break; // switch
- }
- // dribble through into default (like my financial planning ... ?)
-
- default:
-
- goto fail;
- }
-
- // the only way to this point is through the break switches
- // at the end of "rwa" cases
- /* interpret "b" */
- switch( mode[1] ) // this will not even matter if strlen(mode)==1
- {
- case 'b':
- case 'B':
- fp->binary = 1;
- }
-
- setvbuf(fp, NULL, _IOFBF, BUFSIZ);
- return fp;
-
- fail:
-
- // clean up the fp (if necessary) and return error info
- memset( fp, 0, sizeof(FILE) );
-
- fail2:
-
- errno = EINVAL;
- return NULL;
- }
-
- FILE *
- fopenPtr( const Ptr theBlock, const char *mode )
- {
-
- return
- freopenPtr( theBlock, mode, __getfile() );
-
- }
-
- FILE *
- freopenPtr( const Ptr theBlock, const char *mode, FILE *fp )
- {
- Size theBlockSize;
-
- theBlockSize = GetPtrSize(theBlock);
- if ( theBlockSize < 1 ) return(NULL); // reject errors & zero length pointers
-
- return
- freopenblock( (char *) theBlock, mode, theBlockSize, 0, fp );
- }
-
- FILE *
- fopenHandle( const Handle theHandle, const char *mode,
- Size theBlockSizeIncrement )
- {
-
- return
- freopenHandle( theHandle, mode, theBlockSizeIncrement, __getfile() );
-
- }
-
- FILE *
- freopenHandle( const Handle theHandle, const char *mode,
- Size theBlockSizeIncrement, FILE *fp )
- {
-
- Size theHandleSize;
-
- theHandleSize = GetHandleSize(theHandle);
- if ( theHandleSize < 0 )
- {
- return(NULL);
- }
-
- return
- freopenblock( (char *) theHandle, mode,
- - theHandleSize, theBlockSizeIncrement, fp );
- // Cblock->Iblock is responsible for using nonpositive theHandleSize
- // to determine that theHandle is in fact char **, not char *
-
-
- }
-
- /*-snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip-*/
-
-